home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / os2tools / aping / aping.c < prev    next >
Text File  |  1992-06-14  |  27KB  |  763 lines

  1. /*****************************************************************************
  2.  *
  3.  *  MODULE NAME : APING.C
  4.  *
  5.  *  COPYRIGHTS:
  6.  *             This module contains code made available by IBM
  7.  *             Corporation on an AS IS basis.  Any one receiving the
  8.  *             module is considered to be licensed under IBM copyrights
  9.  *             to use the IBM-provided source code in any way he or she
  10.  *             deems fit, including copying it, compiling it, modifying
  11.  *             it, and redistributing it, with or without
  12.  *             modifications.  No license under any IBM patents or
  13.  *             patent applications is to be implied from this copyright
  14.  *             license.
  15.  *
  16.  *             A user of the module should understand that IBM cannot
  17.  *             provide technical support for the module and will not be
  18.  *             responsible for any consequences of use of the program.
  19.  *
  20.  *             Any notices, including this one, are not to be removed
  21.  *             from the module without the prior written consent of
  22.  *             IBM.
  23.  *
  24.  *  AUTHOR:    Peter J. Schwaller
  25.  *             VNET:     PJS at RALVM6           Tie Line: 444-4376
  26.  *             Internet: pjs@ralvm6.vnet.ibm.com     (919) 254-4376
  27.  *
  28.  *  FUNCTION:  Perform an echo test to a specified destination.
  29.  *             APING can be used when you are first installing APPC on
  30.  *             your computer to make sure you can connect to another
  31.  *             computer in the network.  APING can also be used to
  32.  *             get an estimate of the delay time or throughput to another
  33.  *             computer in the network.
  34.  *
  35.  *  AVAILABILITY:
  36.  *             These sample programs and source are also available on
  37.  *             CompuServe through the APPC Information Exchange.  To get
  38.  *             to the APPC forum just type 'GO APPC' from any CompuServe
  39.  *             prompt.  The samples are available in the Sample Programs
  40.  *             library section.  Just search on the keyword CPICPGMS to
  41.  *             find all the samples in this series.
  42.  *
  43.  *             Updates for the sample programs and support for many more
  44.  *             CPI-C platforms will also be made available on CompuServe.
  45.  *
  46.  *  RELATED FILES:
  47.  *             See APING.DOC for detailed information.
  48.  *
  49.  *****************************************************************************/
  50.  
  51. /*****************************************************************************
  52.  * OVERVIEW of APING CPI-C Flows
  53.  *
  54.  *   Client (APING)                      Server (APINGD)
  55.  *   --------------                      ---------------
  56.  * Set up conversation
  57.  *   Allocate       -------------------> Accept Conversation
  58.  * Exchange Version Numbers
  59.  *   Send Data      -------------------> Receive
  60.  *   Receive        <------------------- Send Data
  61.  * For number of iterations (i)
  62.  *  For number of consecutive packets (c)
  63.  *     Send Data    -------------------> Receive
  64.  *  For number of consecutive packets (c)
  65.  *     Receive      <------------------- Send Data
  66.  * Shut down the conversation
  67.  *   Deallocate (FLUSH)
  68.  *****************************************************************************/
  69.  
  70. /* The following definitions are needed for VM and MVS */
  71. #if defined(VM) || defined(MVS)
  72.  
  73. /* All arguments on the command line should be passed to this program. */
  74. #pragma runopts(noexecops)
  75.  
  76. /* The C/370 compiler requires that identifier be unique in the 1st 8 chars. */
  77. #define current_iteration  curr_iteration
  78. #define current_concurrent curr_concurrent
  79.  
  80. #endif
  81.  
  82. /* My CPI-C include file */
  83. /* Hides CMC.H differences among platforms */
  84. #include "cpiccmc.h"
  85.  
  86. /* Collection of routines with special ported version for each platform */
  87. #include "cpicport.h"
  88.  
  89. /* standard C include files */
  90. #include <stdio.h>
  91. #include <stdlib.h>
  92. #include <string.h>
  93. #include <signal.h>
  94.  
  95. #ifndef TIME_NOT_SUPPORTED
  96. #ifndef AIX
  97. #include <time.h>
  98. #else
  99. #include <sys/time.h>
  100. #endif
  101. #endif
  102.  
  103. /* CPI-C error handling routines */
  104. /* This file is supplied with APING */
  105. #include "cpicerr.h"
  106.  
  107. /* CPI-C initialization routines */
  108. /* This file is supplied with APING */
  109. #include "cpicinit.h"
  110.  
  111. /* Argument processing procedure */
  112. /* This file is supplied with APING */
  113. #include "getopt.h"
  114.  
  115.  
  116. /* CPI-C error handling info */
  117. CPICERR * cpicerr;
  118.  
  119.  
  120. /*
  121.  * Max size of a data buffer.  This is the largest size buffer that can
  122.  * be specified on a call to CPI-C.
  123.  */
  124. #define  MAX_SIZE (0x7FFF)
  125.  
  126. /* These are the defaults to be used if the user does not provide arguments  */
  127. /* to override these values.                                                 */
  128. #define  DEFAULT_TP_NAME   "APINGD"
  129. #define  DEFAULT_PARTNER   "NETID.LUNAME"
  130. #define  DEFAULT_MODE_NAME "#INTER"
  131. #define  DEFAULT_SYM_DEST  "APINGD"
  132.  
  133. /* Define these here so we can make changes throughout the code. */
  134. #define  PROGRAM_NAME      "APING"
  135. #define  PROGRAM_INFO      "version 2.2"
  136. #define  MAJOR_VERSION     (2)
  137. #define  MINOR_VERSION     (2)
  138. #define  LOG_FILE_NAME     "aping.err"
  139. #define  LOG_FILE_PATH     "$LOGPATH"
  140.  
  141. #define  ONEWAY_MAJOR_VERSION    (2)
  142. #define  ONEWAY_MINOR_VERSION    (2)
  143.  
  144. /* function prototypes for procedures in this file */
  145. void          exit_processing(void);
  146. void          handler(int);
  147. void process_arguments(int argc,
  148.                        char *argv[],
  149.                        CPICINIT * cpicinit);
  150.  
  151. #ifndef TIME_NOT_SUPPORTED
  152. ULONG         get_time(void);
  153. #endif
  154.  
  155.  
  156. /*
  157.  * The following variables are global to enable their use by the
  158.  * exit_processing() subroutine.
  159.  */
  160. ULONG  number_iterations = 2;               /* times through the loop        */
  161. ULONG  number_concurrent = 1;               /* sends by each side per loop   */
  162. ULONG  current_iteration;                   /* which iteration is active     */
  163. ULONG  current_concurrent;                  /* which send/recv is active     */
  164. #ifndef TIME_NOT_SUPPORTED
  165. ULONG  total_time = 0;                      /* used to calculate averages    */
  166. ULONG  min_time = 0xFFFFFFFF;               /* used for max elapsed time     */
  167. ULONG  max_time = 0;                        /* used for min elapsed time     */
  168. double data_rate;                           /* Variable used to calculate    */
  169.                                             /* the data rate                 */
  170. #endif
  171. ULONG  size = 100;                          /* size of data sends            */
  172.  
  173. int    one_way_flag = 2;                    /* Was one way data requested    */
  174.                                             /* value of 2 means two way echo */
  175.                                             /* value of 1 means one way      */
  176.  
  177. /*
  178.  * Message displayed with show_info() when APING is started.
  179.  */
  180. char * intro[] = {
  181.     PROGRAM_NAME " " PROGRAM_INFO " APPC echo test with timings.",
  182.     "  by Peter J. Schwaller (pjs@ralvm6.vnet.ibm.com)",
  183.     NULL
  184.     };
  185.  
  186. /*
  187.  * Message displayed with show_info() when usage information is requested or
  188.  * after an invalid flag was specified.
  189.  */
  190. char * usage[] = {
  191.     "",
  192.     "APING [flags] destination",
  193.     "  destination",
  194.     "\tmay be either a symbolic destination name or a partner LU name",
  195.     "  -m mode_name",
  196.     "\tmode name (default: #BATCH)",
  197.     "  -t tp_name",
  198.     "\tthe TP to start on the server (default: APINGD)",
  199.     "  -s N",
  200.     "\tN is the size of the packet transmitted (default: 100 bytes)",
  201.     "  -i N",
  202.     "\tN is the number of iterations (default: 2)",
  203.     "  -c N",
  204.     "\tN is the number of consecutive packets sent by each side (default: 1)",
  205.     "  -1",
  206.     "\tOnly send data from client to server (No echo)",
  207.     "  -u userid",
  208.     "  -p password",
  209.     "\tSecurity parameters.  If a userid is specified without a password,",
  210.     "\tyou will be prompted for the password.",
  211.     "  -n",
  212.     "\tDo not use any security (SECURITY=NONE).",
  213.     "",
  214. #ifndef TIME_NOT_SUPPORTED
  215.     "The minimum time, maximum time, and average time will be shown.",
  216. #endif
  217.     NULL
  218.     };
  219.  
  220.  
  221. void cdecl
  222. main( int argc, char *argv[])
  223. {
  224.     /* Variables used for CPI-C calls */
  225.     unsigned char cm_conv_id[8];            /* CPI-C conversation ID         */
  226.     CM_INT32    cm_rc;                      /* CPI-C return code             */
  227.     CM_INT32    length;                     /* generic length variable       */
  228.     CM_INT32    rts_received;               /* request to send received      */
  229.     CM_INT32    max_receive_len;            /* Max receive length on CMRCV   */
  230.     CM_INT32    what_received;              /* What received parm from CMRCV */
  231.     CM_INT32    received_len;               /* Amount of data rcvd on CMRCV  */
  232.     CM_INT32    status_received;            /* Status from CMRCV             */
  233.  
  234.     /* Data buffer for send and receive */
  235.     unsigned char CM_PTR buffer;            /* CPIC data buffer              */
  236.  
  237.     /* Destination information */
  238.     CPICINIT * cpicinit;
  239.  
  240. #ifndef TIME_NOT_SUPPORTED
  241.     ULONG       start_time = 0;             /* when a ping starts            */
  242.     ULONG       end_time;                   /* when a ping ends              */
  243.     ULONG       elapsed_time;               /* used for time calculations    */
  244. #endif
  245.  
  246.     char partner_major_version;
  247.     char partner_minor_version;
  248.  
  249.  
  250.     /*
  251.      * Make sure all output is seen as soon as possible.
  252.      */
  253.     setbuf(stdout, NULL);
  254.  
  255.     show_info(intro);                       /* Show program information      */
  256.  
  257.  
  258.     /*
  259.      * Create a new CPICINIT structure and initialize values.
  260.      * The procedures are in CPICINIT.C
  261.      */
  262.  
  263.     cpicinit = cpicinit_new();
  264.     cpicinit_default_tp_name(cpicinit, DEFAULT_TP_NAME);
  265.     cpicinit_default_destination(cpicinit, DEFAULT_PARTNER);
  266.     cpicinit_default_mode_name(cpicinit, DEFAULT_MODE_NAME);
  267.     cpicinit_default_sym_dest_name(cpicinit, DEFAULT_SYM_DEST);
  268.  
  269.     /*
  270.      * Process all of the command line arguments.  All of the conversation
  271.      * setup arguments are stored in the cpicinit object.  The block size
  272.      * and other loop parameters are set in the global variables.
  273.      */
  274.     process_arguments(argc, argv, cpicinit);
  275.  
  276.  
  277.     if (cpicinit->set_destination == NOT_SET) {
  278.         fprintf(stderr, "\n\aYou must specify a destination.\n");
  279.         show_info(usage);
  280.         exit(EXIT_FAILURE);
  281.     }
  282.  
  283.     if (cpicinit_query_passwd_required(cpicinit)) {
  284.         /* get a password from the user */
  285.         cpicinit_get_passwd(cpicinit);
  286.     }
  287.  
  288. #if 0
  289.     /* set up a signal handler, to clean up and display total upon exit */
  290.     if (signal(SIGINT, SIG_IGN) == SIG_DFL)
  291.         signal(SIGINT, handler);
  292. #endif
  293.  
  294.     buffer = (unsigned char CM_PTR)alloc_cpic_buffer((USHORT)size);
  295.                                             /* allocate an APPC buffer       */
  296.  
  297.  
  298.  
  299.     /*
  300.      * Initialize the CPICERR structure.  This is done before the CMINIT
  301.      * call so that we can use CPICERR for help with errors on CMINIT.
  302.      * The procedure is in CPICERR.C
  303.      */
  304.     cpicerr = cpicerr_new();
  305.     cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
  306.     cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
  307.     cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
  308.     cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
  309.     cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
  310.     cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
  311.  
  312.     cpicinit_setup_conversation(cpicinit, cm_conv_id, cpicerr);
  313.  
  314.     /*
  315.      * Fill in conversation information for CPI-C error reporting.
  316.      */
  317.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  318.  
  319.     {
  320.     CM_SYNC_LEVEL sync_level = CM_CONFIRM;
  321.     cmssl(cm_conv_id,                       /* Set sync level                */
  322.           &sync_level,
  323.           &cm_rc);
  324.     /* The only expected return code is CM_OK */
  325.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSSL, cm_rc);
  326.     }
  327.  
  328.     {
  329.     CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
  330.     cmsptr(cm_conv_id,                      /* Set prepare to receive type   */
  331.            &prep_to_receive,
  332.            &cm_rc);
  333.     /* The only expected return code is CM_OK */
  334.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
  335.     }
  336.  
  337.  
  338.     /*
  339.      * Fill in conversation information for CPI-C error reporting.
  340.      */
  341.     cpicerr_set_conv_id(cpicerr, cm_conv_id);
  342.  
  343. #ifndef TIME_NOT_SUPPORTED
  344.     start_time = get_time();            /* let's time the allocate       */
  345. #endif
  346.  
  347.     cmallc(cm_conv_id,
  348.            &cm_rc);
  349.     /* The only expected return code is CM_OK */
  350.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMALLC, cm_rc);
  351.  
  352. #ifndef TIME_NOT_SUPPORTED
  353.     end_time = get_time();                  /* stop the timer                */
  354.  
  355.                                             /* show the allocate time        */
  356.     printf("\nAllocate duration:                     %8lu ms\n",
  357.                                                        end_time - start_time);
  358. #endif
  359.  
  360. #ifndef TIME_NOT_SUPPORTED
  361.     start_time = get_time();
  362. #endif
  363.  
  364.     cpicerr_exchange_version(cpicerr,
  365.                              cm_conv_id,
  366.                              CM_SEND_STATE,
  367.                              &partner_major_version,
  368.                              &partner_minor_version);
  369.  
  370.     /*
  371.      * If the one_way_flag has been set, we have to make sure that our
  372.      * partner is at the correct version to accept one way data.  If
  373.      * the partner is not at the right level, we'll turn off the one
  374.      * way flag and the partner will echo data (normal operating mode).
  375.      *
  376.      * Trying to use one way data with a partner that can't handle the
  377.      * CONFIRM status indicator would result in an error on the partner
  378.      * side.  On this side, we would see DEALLOCATE_ABEND.
  379.      */
  380.     if ((one_way_flag == 1)  &&
  381.         !(partner_major_version > ONEWAY_MAJOR_VERSION ||
  382.         (partner_major_version == ONEWAY_MAJOR_VERSION &&
  383.          partner_minor_version >= ONEWAY_MINOR_VERSION))) {
  384.         printf("\nOne way data transfer is not supported by partner.\n");
  385.         printf("Partner will echo data.\n");
  386.         one_way_flag = 2;
  387.     }
  388.  
  389. #ifndef TIME_NOT_SUPPORTED
  390.     end_time = get_time();                  /* stop the timer                */
  391.  
  392.                                             /* show the startup time         */
  393.     printf("\nProgram startup and Confirm duration:  %8lu ms\n\n",
  394.                                                        end_time - start_time);
  395. #endif
  396.  
  397.  
  398.     printf(
  399.     "        Duration        Data Sent        Data Rate        Data Rate\n");
  400.     printf(
  401.     "        (msec)          (bytes)          (KB/s)           (Mb/s)   \n");
  402.     printf(
  403.     "        --------        ---------        ---------        ---------\n");
  404.  
  405.  
  406.     /*
  407.      * Start current at zero so if a BREAK occurs, it will contain the number
  408.      * of iterations completed.  We take a slight risk in assuming that
  409.      * the current_iteration++ operation is atomic.
  410.      *
  411.      * This loop encompasses both a send loop and a receive loop.  Both
  412.      * the send a receive loop are executed the number of times specified
  413.      * by the number_iterations variable (set by the -i argument).
  414.      */
  415.     for (current_iteration = 0;
  416.          current_iteration<number_iterations;
  417.          current_iteration++ ) {
  418.         {
  419.         CM_SEND_TYPE send_type = CM_BUFFER_DATA;
  420.         cmsst(cm_conv_id,
  421.               &send_type,
  422.               &cm_rc);
  423.         if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  424.         }
  425.  
  426. #ifndef TIME_NOT_SUPPORTED
  427.         start_time = get_time();
  428. #endif
  429.  
  430.         for (current_concurrent = 1;        /* Start current at one so we    */
  431.              current_concurrent<number_concurrent ; /* do one LESS send in   */
  432.              current_concurrent++ ) {       /* loop than the specifed number */
  433.  
  434.             length = size;
  435.             cmsend(cm_conv_id,
  436.                    buffer,
  437.                    &length,
  438.                    &rts_received,
  439.                    &cm_rc);
  440.  
  441.             /* The only expected return code is CM_OK */
  442.             if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  443.  
  444.         }
  445.  
  446.         /*
  447.          * Set the send type to do a send and a prepare to receive.  This will
  448.          * send both the data and the send permission indicator to our
  449.          * partner all at once.
  450.          *
  451.          * If the one_way_flag has been set, we will issue a Confirm along
  452.          * with the Send_Data.  This will allow us to know when the partner
  453.          * has actually received all the data so we can get an accurate
  454.          * timing.
  455.          *
  456.          * On the partner side, if Send status is received, the partner will
  457.          * know to echo the data.  If Confirm status is received, the partner
  458.          * will know to issued Confirmed and then get ready to receive
  459.          * more data, since the partner won't be echoing.
  460.          */
  461.         {
  462.         CM_SEND_TYPE send_type;
  463.         if (one_way_flag != 1) {
  464.             send_type = CM_SEND_AND_PREP_TO_RECEIVE;
  465.         } else {
  466.             send_type = CM_SEND_AND_CONFIRM;
  467.         }
  468.         cmsst(cm_conv_id,
  469.               &send_type,
  470.               &cm_rc);
  471.         if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
  472.         }
  473.  
  474.         length = size;
  475.         cmsend(cm_conv_id,
  476.                buffer,
  477.                &length,
  478.                &rts_received,
  479.                &cm_rc);
  480.         /* The only expected return code is CM_OK */
  481.         if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
  482.  
  483.         if (one_way_flag != 1) {
  484.             max_receive_len = size;
  485.             do {
  486.  
  487.                 cmrcv (cm_conv_id,          /* Receive Data                  */
  488.                        buffer,              /* Data Pointer                  */
  489.                        &max_receive_len,    /* Size of Data Buffer           */
  490.                        &what_received,      /* returned - what received      */
  491.                        &received_len,       /* returned - length of data     */
  492.                        &status_received,    /* returned - status received    */
  493.                        &rts_received,       /* returned - request to send    */
  494.                        &cm_rc);
  495.                 /* The only expected return code is CM_OK */
  496.                 if (cm_rc != CM_OK) {
  497.                     cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
  498.                 }
  499.  
  500.                 if (what_received != CM_NO_DATA_RECEIVED) {
  501.                     current_concurrent--;
  502.                 }
  503.  
  504.             } while ((status_received !=  CM_SEND_RECEIVED));
  505.             /* Repeat the receive loop until SEND permission has been rcvd. */
  506.  
  507.             if (current_concurrent != 0) {
  508.                 fprintf(stderr,
  509.                 "ERROR.\n");
  510.                 fprintf(stderr,
  511.                     "Partner did not send the expected number of records.\n");
  512.             }
  513.         } else {
  514.         }
  515.  
  516. #ifndef TIME_NOT_SUPPORTED
  517.         end_time = get_time();              /* stop timer                    */
  518.  
  519.         elapsed_time = end_time - start_time; /* calculate elapsed time      */
  520.  
  521.         printf("%16ld", elapsed_time);
  522.         printf("%17lu", size * number_concurrent * one_way_flag);
  523.  
  524.         if (elapsed_time) {
  525.             data_rate =                     /* in KBytes / 0.1 Sec           */
  526.                               (double)
  527.               ( ( (((double)size * (double)number_concurrent) / (double)1024) *
  528.                    (double)1 * (double)1000 * (double)one_way_flag)
  529.                            /    /* divided by */
  530.                  ( (double)elapsed_time  / (double)10)  );
  531.  
  532.             data_rate = data_rate / (double)10;
  533.  
  534.             printf("%17.1f", data_rate);
  535.             printf("%17.3f\n", (data_rate * (double)8) / (double)1000);
  536.  
  537.         } else {
  538.             printf("\n");                   /* Make sure we move to next line*/
  539.         }
  540.  
  541.         total_time += elapsed_time;         /* accumulate the elapsed time   */
  542.  
  543.         if (elapsed_time > max_time) {
  544.             max_time = elapsed_time;        /* set the max time              */
  545.         }
  546.         if (elapsed_time < min_time) {
  547.             min_time = elapsed_time;        /* set the min time              */
  548.         }
  549. #else
  550.         printf("Ping completed\n");
  551. #endif
  552.  
  553.     }
  554.  
  555.     {
  556.     CM_DEALLOCATE_TYPE deallocate_type = CM_DEALLOCATE_FLUSH;
  557.     cmsdt(cm_conv_id,
  558.           &deallocate_type,
  559.           &cm_rc);
  560.     /* The only expected return code is CM_OK */
  561.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSDT, cm_rc);
  562.     }
  563.  
  564.     cmdeal(cm_conv_id,
  565.            &cm_rc);
  566.     /* The only expected return code is CM_OK */
  567.     if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMDEAL, cm_rc);
  568.  
  569.     /* destroy the object we created with cpicinit_new() */
  570.     cpicinit_destroy(cpicinit);
  571.  
  572.     /* destroy the object we created with cpicerr_new() */
  573.     cpicerr_destroy(cpicerr);
  574.  
  575.     exit_processing();                      /* to avoid losing printouts     */
  576.                                             /* if redirected.                */
  577.     exit(EXIT_SUCCESS);                     /* force exit_list processing    */
  578.  
  579. }
  580.  
  581. void
  582. process_arguments(int argc,
  583.                   char *argv[],
  584.                   CPICINIT * cpicinit)
  585. {
  586.     int         c;                          /* flag specifed, used w/getopt  */
  587.  
  588.     /*
  589.      * GETOPT is an easy way to parse command line arguments
  590.      * Each parameter which can have a flag is passed in the third argument
  591.      * to getopt.  Getopt returns the character of the flag on the command
  592.      * line and sets optarg to point to the value associated with the flag.
  593.      * optind is the index of the argument that getopt is currently processing.
  594.      */
  595.     while (optind != argc) {
  596.         c = getopt(argc, argv, "?1c:t:m:i:s:u:p:C:T:M:I:S:U:P:nN");
  597.         switch (c) {
  598.         case EOF:
  599.             optarg = argv[optind];
  600.             if (optarg[0] == '?') {
  601.                show_info(usage);
  602.                exit(EXIT_FAILURE);
  603.             }
  604.             optind++;
  605.             if (cpicinit->set_destination == NOT_SET) {
  606.                 cpicinit_set_destination(cpicinit, optarg);
  607.             } else {
  608.                 fprintf(stderr, "Only one destination may be specified.\n");
  609.             }
  610.             break;
  611.         case 'M':
  612.         case 'm':
  613.             cpicinit_set_mode_name(cpicinit, optarg);
  614.             break;
  615.         case 'T':
  616.         case 't':
  617.             cpicinit_set_tp_name(cpicinit,optarg);
  618.             break;
  619.         case 'U':
  620.         case 'u':
  621.             cpicinit_set_userid(cpicinit, optarg);
  622.             break;
  623.         case 'P':
  624.         case 'p':
  625.             cpicinit_set_passwd(cpicinit, optarg);
  626.             break;
  627.         case 'N':
  628.         case 'n':
  629.             cpicinit_set_security_none(cpicinit);
  630.             break;
  631.         case 'S':
  632.         case 's':
  633.             size = atol(optarg);            /* get the size of send blocks   */
  634.             if (size > MAX_SIZE) {          /* check bounds                  */
  635.                 printf("Size (-s) of %lu too large.\n"
  636.                        "Setting to %lu\n", size, (unsigned long)MAX_SIZE);
  637.                 size = MAX_SIZE;            /* reset to MAX                  */
  638.             }
  639.             break;
  640.         case 'I':
  641.         case 'i':
  642.             number_iterations = atol(optarg);
  643.             break;
  644.         case 'C':
  645.         case 'c':
  646.             number_concurrent = atol(optarg);
  647.             break;
  648.         case '1':
  649.             one_way_flag = 1;
  650.             break;
  651.         case '?':
  652.             show_info(usage);
  653.             exit(EXIT_FAILURE);
  654.             break;
  655.         default:
  656.             printf("Invalid flag.  Use %s -? for usage\n", PROGRAM_NAME);
  657.             exit(EXIT_FAILURE);
  658.         }
  659.     }
  660. }
  661.  
  662.  
  663. #ifndef TIME_NOT_SUPPORTED
  664. ULONG
  665. /* returns time in milliseconds */
  666. get_time(void)
  667. {
  668.  
  669. #if defined(OS2) || defined(FAPI) || defined(DOS)
  670.     /*
  671.      * clock() returns valid information on OS/2 and DOS since no distinction
  672.      * is made between process time and time of day.
  673.      */
  674.     clock_t time;
  675.     time = clock();
  676.     return (time / (CLK_TCK / 1000));
  677. #elif defined(AIX)
  678.     time_t ltime;
  679.     struct timestruc_t TimeStruct;
  680.  
  681.     if (gettimer(TIMEOFDAY, &TimeStruct) == 0) {
  682.         return ((1000 * TimeStruct.tv_sec) + (TimeStruct.tv_nsec / 1000000));
  683.     } else {
  684.         time(<ime);
  685.         return 1000 * ltime;
  686.     }
  687.  
  688. #else
  689.     /*
  690.      * Other systems must use the time() calls to get the time of day in
  691.      * seconds.  This results in very coarse timings.
  692.      */
  693.     time_t ltime;
  694.     time(<ime);
  695.     return 1000 * ltime;
  696. #endif
  697.  
  698. }
  699. #endif
  700.  
  701. void handler(int sig)
  702. {
  703.     /*=========================================================================
  704.      * This is the signal handler.
  705.      * Input parameter "sig" is not used, but required by the function
  706.      * prototype for the signal() library call.
  707.      *=======================================================================*/
  708.  
  709.     (void)signal(SIGINT, SIG_IGN);
  710.     exit_processing();
  711.     exit(EXIT_FAILURE);
  712. }
  713.  
  714.  
  715. void exit_processing(void)
  716. /*
  717.  * Print out the grand totals and max/min times.
  718.  */
  719. {
  720.  
  721.     double data_rate;
  722.     static int beenhere = 0;
  723.  
  724.  
  725. #ifndef TIME_NOT_SUPPORTED
  726.     if (!beenhere) {                        /* avoid being printing twice    */
  727.         beenhere = 1;
  728.  
  729.         if (total_time > 10) {
  730.  
  731.             data_rate =                     /* in KBytes / 0.1 Sec           */
  732.                               (double)
  733.               ( ( (((double)size * (double)number_concurrent) / (double)1024) *
  734.                 (double)current_iteration * (double)1000 * (double)one_way_flag)
  735.                            /    /* divided by */
  736.                  ( (double)total_time  / (double)10)  );
  737.  
  738.             data_rate = data_rate / 10;
  739.  
  740.             printf("Totals:%9lu", total_time);
  741.             printf("%17lu", size *
  742.                             number_concurrent *
  743.                             current_iteration *
  744.                             one_way_flag);
  745.             printf("%17.1f", data_rate);
  746.             printf("%17.3f\n", (data_rate * (double)8) / (double)1000);
  747.         if (current_iteration > 0) {
  748.             printf(
  749.             "\nDuration statistics:   Min = %lu   Ave = %lu   Max = %lu\n",
  750.                                              min_time,
  751.                                              total_time / current_iteration,
  752.                                              max_time);
  753.         }
  754.         } else {
  755.             printf("\n");
  756.         }
  757.     }
  758. #endif
  759.  
  760. }
  761.  
  762.  
  763.